//--------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>

#include "dkbasic.h"
#include "dkevents.h"
#include "dktimer.h"
#include "dkprogram.h"
#include "dkstatements.h"

//--------------------------------------------------------------------

// error handlers (ON ERROR x GOTO y)
struct _dk_errorhandler *dk_errorhandlers;


volatile uint8_t dkeventflags=0;		// bitmapped for each type of event that is enabled
uint8_t dkeventmasks=0;

uint8_t dkevent_key=0;		// set to value of last KEY event (only most recent KEY event is kept)

uint16_t dkevent_com_handlers[NUM_COM_HANDLERS];		// line number for handlers for COM0: and COM1:
uint16_t dkevent_key_handlers[NUM_KEY_HANDLERS];		// event handlers 1-20 for KEY()
uint16_t dkevent_timer_handlers[NUM_TIMER_HANDLERS];	// handler for TIMER()
uint16_t dkevent_pin_handlers[NUM_PIN_HANDLERS];		// handler for PIN()

uint16_t dkpin_flags=0;		// bitmapped for 16 PIN events
uint16_t dkpin_masks=0;

struct _dkpin dkpins[ NUM_PIN_HANDLERS ];


//--------------------------------------------------------------------
// TODO: should events be disabled while one is being handled? stuff like many com bytes could be problem
//  event can be turned off in handler (only one event can fire for every program line executed, but they can be nested)
// should have a global 'events disable' statement?
int dkhandle_event( void )
{
	struct _dkgosub *gosubptr;
	uint8_t activeevents;
	uint16_t eventlinenum=0;
	int i;	
	

	activeevents = dkeventflags & dkeventmasks;
	
	if( activeevents & DK_EVENT_PIN )
	{
		for( i=0; i<NUM_PIN_HANDLERS; i++ )
		{
			if( !((1<<i) & dkpin_masks) )
				continue;
				
			if( ((uint8_t *)dkpins[i].addr)[0] & (1<<dkpins[i].bit) )
			{							// pin is at high level
				if( dkpins[i].value&(1<<7) )
					continue;			// high level of pin has already been seen
				if( !(dkpins[i].value&1) )
				{						// event is on low level
					dkpins[i].value |= (1<<7);
					continue;
				}
				dkpins[i].value |= (1<<7);
			}
			else
			{							// pin is at low level
				if( !( dkpins[i].value&(1<<7) ) )
					continue;			// low level of pin has already been seen
				if( dkpins[i].value&1 )
				{						// event is on high level
					dkpins[i].value &= (~(1<<7));
					continue;
				}
				dkpins[i].value &= (~(1<<7));
			}
			eventlinenum = dkevent_pin_handlers[i];
		}
	}
	else if( activeevents & DK_EVENT_COM0 )
	{													// handle COM0 event
		eventlinenum = dkevent_com_handlers[0];
		
		dkeventflags &= (~DK_EVENT_COM0);
	}
	else if( activeevents & DK_EVENT_COM1 )
	{													// handle COM1 event
		eventlinenum = dkevent_com_handlers[1];
		
		dkeventflags &= (~DK_EVENT_COM1);
	}
	else if( activeevents & DK_EVENT_TIMER )
	{													// handle TIMER event		
		for( i=0; i<NUM_TIMER_HANDLERS; i++ )
		{
			if( dktimer_flags & (1<<i) & dktimer_masks )
			{
				eventlinenum = dkevent_timer_handlers[i];
				dktimer_flags &= (~(1<<i));
				break;
			}
		}
		if( ! (dktimer_flags&dktimer_masks) )
			dkeventflags &= (~DK_EVENT_TIMER);
	}
	
	
	if( eventlinenum )
	{
		gosubptr = (struct _dkgosub *)malloc( sizeof( struct _dkgosub ) );
		if( !gosubptr )
		{
			dkstatus = DKSTATUS_OUTOFMEMORY;
			return -1;
		}
		gosubptr->gosublinenum = dkPC;
		gosubptr->next = dkgosubstack;	// link new struct _dkgosub into list
		dkgosubstack = gosubptr;
	
		return eventlinenum;
	}


	return 0;
}
//--------------------------------------------------------------------

